home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1999-06-16 | 43.6 KB | 1,576 lines | [ TEXT/MPS ]
/* File: menus.c Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved. */ // // You may incorporate this sample code into your applications // without restriction. This sample code has been provided "AS // IS" and the responsibility for its operation is 100% yours. // You are not permitted to redistribute the source as "Apple // sample code" after having made changes. If you're going to // re-distribute the source, we require that you make it clear // in the source that the code was descended from Apple sample // code, but that you've made changes. // #pragma segment AppSeg #ifndef __SCRAP__ #include <Scrap.h> #endif #ifndef __DEVICES__ #include <Devices.h> #endif #ifndef __TOOLUTILS__ #include <ToolUtils.h> #endif #ifndef __LISTS__ #include <Lists.h> #endif #ifndef __SOUND__ #include <Sound.h> #endif #ifndef Common_Defs #include "Common.h" #endif // prototypes: void SetItemEnable( MenuHandle theMenu, short theItem, short enable ); short DoPaste( ); void DoAbout( ); // protos for using the Nav dialogs: OSErr DoSelectDictionary( void ); OSErr DoSelectDirectory( void ); OSErr DoSelectObject( void ); OSErr DoSelectVolume( void ); OSErr DoCreateFolder( void ); // open customization example: OSErr DoCustomOpen( void ); pascal void myCustomEventProc( NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, NavCallBackUserData callBackUD ); void HandleCustomMouseDown( NavCBRecPtr callBackParms ); void HandleCommandPopup( ControlHandle thePopup, NavCBRecPtr callBackParms ); // for add/remove example: pascal void myCustomAddRemoveEventProc( NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, NavCallBackUserData callBackUD ); void HandleAddRemoveCustomMouseDown( NavCBRecPtr callBackParms ); OSErr DoCustomAddRemove( void ); Boolean DoListMouseDown( NavCBRecPtr callBackParms ); void HandleAdd( NavCBRecPtr callBackParms, AEDescList fileList ); void HandleRemove( NavCBRecPtr callBackParms ); void HandleRemoveAll( NavCBRecPtr callBackParms ); Boolean DoAddItem( unsigned char* theData, short size ); void AdjustAddButton( NavCBRecPtr callBackParms ); Boolean DoSearch( AEDesc searchDesc ); // custom dialog item: #define kControlListID 132 #define kPopupCommand 1 #define kAddRemoveControlListID 133 #define iList 1 #define iAddButton 2 #define iRemoveButton 3 #define iRemoveAllButton 4 #define iDoneButton 5 // the requested dimensions for our sample open customization area: #define kCustomWidth 100 #define kCustomHeight 40 // the requested dimensions for our add remove customization area: #define kAddRemoveCustomWidth 400 #define kAddRemoveCustomHeight 125 extern Document* gDocumentList[kMaxDocumentCount]; extern short gDocumentCount; extern short gCanUndoDrag; extern short gQuit, gQuitting; extern Boolean gNavServicesExists; // customization globals: Handle gDitlList; MenuHandle gPopupMenu; short gLastTryWidth; short gLastTryHeight; ListHandle gListItem; long gNumItems; Rect gOriginalRect; // ***************************************************************************** // * // * SetItemEnable() // * // ***************************************************************************** void SetItemEnable(MenuHandle theMenu, short theItem, short enable) { if (enable) EnableItem(theMenu,theItem); else DisableItem(theMenu,theItem); } // ***************************************************************************** // * // * AdjustMenus() // * // ***************************************************************************** void AdjustMenus() { MenuHandle theMenu; Document* theDocument; short teSelection = 0; Str255 theStr; theDocument = IsDocumentWindow((WindowPtr)FrontWindow()); if (theDocument->theTE != NULL) teSelection = (theDocument) && ((**(theDocument->theTE)).selStart != (**(theDocument->theTE)).selEnd); theMenu = GetMenuHandle(idFileMenu); SetItemEnable(theMenu,NewItem,gDocumentCount < kMaxDocumentCount); SetItemEnable(theMenu,OpenItem,gDocumentCount < kMaxDocumentCount); SetItemEnable(theMenu,CloseItem,theDocument != 0L); SetItemEnable(theMenu,SaveItem,(theDocument) && (theDocument->dirty)); SetItemEnable(theMenu,RevertItem,(theDocument) && (theDocument->dirty) && (theDocument->fRefNum)); SetItemEnable(theMenu,SaveACopyItem,theDocument != 0L); SetItemEnable(theMenu,DictionaryItem,gNavServicesExists); theMenu = GetMenuHandle(idEditMenu); GetIndString(theStr,MenuStringsID,gCanUndoDrag); SetMenuItemText(theMenu,iUndo,theStr); SetItemEnable(theMenu,iUndo,gCanUndoDrag != slCantUndo); SetItemEnable(theMenu,iCut,teSelection); SetItemEnable(theMenu,iCopy,teSelection); SetItemEnable(theMenu,iPaste,theDocument != 0L); SetItemEnable(theMenu,iClear,teSelection); SetItemEnable(theMenu,iSelectAll,theDocument != 0L); theMenu = GetMenuHandle(idUtilsMenu); SetItemEnable(theMenu,iSelectDir,gNavServicesExists); SetItemEnable(theMenu,iSelectVol,gNavServicesExists); SetItemEnable(theMenu,iSelectObject,gNavServicesExists); SetItemEnable(theMenu,iCreateFolder,gNavServicesExists); SetItemEnable(theMenu,iCustomOpen,gNavServicesExists); SetItemEnable(theMenu,iAddFiles,gNavServicesExists); } // ***************************************************************************** // * // * DoPaste() // * // ***************************************************************************** short DoPaste() { long size, offset; Handle theData; size = GetScrap(0L,'UPRC',&offset); if (size <= 0) return(0); theData = NewHandle(size); GetScrap(theData,'UPRC',&offset); HLock(theData); PutScrap(size,'test',*theData); HUnlock(theData); DisposeHandle(theData); return noErr; } // ***************************************************************************** // * // * DoSelectDictionary() // * // ***************************************************************************** OSErr DoSelectDictionary() { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavEventUPP eventUPP = NewNavEventProc(myEventProc); NavTypeListHandle openList = NULL; // use the default location for the dialog: theErr = NavGetDefaultDialogOptions(&dialogOptions); GetIndString(dialogOptions.message,rAppStringsID,sChooseFile); dialogOptions.preferenceKey = kSelectFilePrefKey; openList = (NavTypeListHandle)GetResource(kOpenRsrcType,kOpenRsrcID2); theErr = NavChooseFile( NULL, &theReply, &dialogOptions, eventUPP, NULL, NULL, openList, (NavCallBackUserData)&gDocumentList); DisposeRoutineDescriptor(eventUPP); if ( theReply.validRecord && theErr == noErr ) { // grab the target FSSpec from the AEDesc: FSSpec finalFSSpec; AEDesc resultDesc; if ((theErr = AECoerceDesc( &(theReply.selection), typeFSS, &resultDesc )) == noErr) if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalFSSpec, sizeof ( FSSpec ), NULL )) == noErr) { // 'finalFSSpec' is the chosen file… } AEDisposeDesc(&resultDesc); theErr = NavDisposeReply(&theReply); } if (openList != NULL) DisposeHandle((Handle)openList); return theErr; } // ***************************************************************************** // * // * DoSelectDirectory() // * // ***************************************************************************** OSErr DoSelectDirectory() { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavEventUPP eventUPP = NewNavEventProc(myEventProc); theErr = NavGetDefaultDialogOptions(&dialogOptions); GetIndString(dialogOptions.message,rAppStringsID,sChooseFolder); dialogOptions.preferenceKey = kSelectFolderPrefKey; theErr = NavChooseFolder( NULL, &theReply, &dialogOptions, eventUPP, NULL, (NavCallBackUserData)&gDocumentList); DisposeRoutineDescriptor(eventUPP); if ((theReply.validRecord)&&(theErr == noErr)) { // grab the target FSSpec from the AEDesc: FSSpec finalFSSpec; AEDesc resultDesc; if ((theErr = AECoerceDesc(&(theReply.selection),typeFSS,&resultDesc)) == noErr) if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalFSSpec, sizeof ( FSSpec ), NULL )) == noErr) { // 'finalFSSpec' is the selected directory… } AEDisposeDesc(&resultDesc); theErr = NavDisposeReply(&theReply); } return theErr; } // ***************************************************************************** // * // * DoSelectObject() // * // ***************************************************************************** OSErr DoSelectObject() { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavEventUPP eventUPP = NewNavEventProc(myEventProc); theErr = NavGetDefaultDialogOptions(&dialogOptions); GetIndString(dialogOptions.message,rAppStringsID,sChooseObject); dialogOptions.preferenceKey = kSelectObjectPrefKey; theErr = NavChooseObject( NULL, &theReply, &dialogOptions, eventUPP, NULL, (NavCallBackUserData)&gDocumentList); DisposeRoutineDescriptor(eventUPP); if ((theReply.validRecord)&&(theErr == noErr)) { // grab the target FSSpec from the AEDesc: FSSpec finalFSSpec; AEDesc resultDesc; if ((theErr = AECoerceDesc(&(theReply.selection),typeFSS,&resultDesc)) == noErr) if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalFSSpec, sizeof ( FSSpec ), NULL )) == noErr) { // 'finalFSSpec' is the selected directory… } AEDisposeDesc(&resultDesc); theErr = NavDisposeReply(&theReply); } return theErr; } // ***************************************************************************** // * // * DoSelectVolume() // * // ***************************************************************************** OSErr DoSelectVolume() { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavEventUPP eventUPP = NewNavEventProc(myEventProc); // use the default location for the dialog: theErr = NavGetDefaultDialogOptions(&dialogOptions); GetIndString(dialogOptions.message,rAppStringsID,sChooseVolume); dialogOptions.preferenceKey = kSelectVolumePrefKey; theErr = NavChooseVolume( NULL, &theReply, &dialogOptions, eventUPP, NULL, (NavCallBackUserData)&gDocumentList); if ((theReply.validRecord)&&(theErr == noErr)) { // grab the target FSSpec from the AEDesc: FSSpec finalFSSpec; AEDesc resultDesc; // there is only one selection here we get only the first AEDesc: if ((theErr = AECoerceDesc(&(theReply.selection),typeFSS,&resultDesc)) == noErr) if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalFSSpec, sizeof ( FSSpec ), NULL )) == noErr) { // 'finalFSSpec' is the chosen volume… } AEDisposeDesc(&resultDesc); theErr = NavDisposeReply(&theReply); } DisposeRoutineDescriptor(eventUPP); return theErr; } // ***************************************************************************** // * // * DoCreateFolder() // * // ***************************************************************************** OSErr DoCreateFolder() { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavEventUPP eventUPP = NewNavEventProc(myEventProc); // use the default location for the dialog: theErr = NavGetDefaultDialogOptions(&dialogOptions); GetIndString(dialogOptions.message,rAppStringsID,sCreateFolder); dialogOptions.preferenceKey = kNewFolderPrefKey; theErr = NavNewFolder( NULL, &theReply, &dialogOptions, eventUPP, (NavCallBackUserData)&gDocumentList); if (theReply.validRecord) { // grab the target FSSpec from the AEDesc: FSSpec finalFSSpec; AEDesc resultDesc; // there is only one selection here so we get the first AEDesc: if ((theErr = AECoerceDesc(&(theReply.selection),typeFSS,&resultDesc)) == noErr) if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalFSSpec, sizeof ( FSSpec ), NULL )) == noErr) { // 'finalFSSpec' is the newly created folder… } AEDisposeDesc(&resultDesc); theErr = NavDisposeReply(&theReply); } return theErr; } // ***************************************************************************** // * // * HandleCommandPopup() // * // ***************************************************************************** void HandleCommandPopup(ControlHandle thePopup, NavCBRecPtr callBackParms) { OSErr theErr = noErr; short selection = 0; selection = GetControlValue(thePopup)-1; switch (selection) { case kNavCtlShowDesktop: case kNavCtlScrollHome: case kNavCtlScrollEnd: case kNavCtlPageUp: case kNavCtlPageDown: theErr = NavCustomControl(callBackParms->context,selection,NULL); break; case kNavCtlShowSelection: theErr = NavCustomControl(callBackParms->context,kNavCtlShowSelection,NULL); break; case kNavCtlOpenSelection: { AEDesc itemToOpen; theErr = NavCustomControl(callBackParms->context,kNavCtlOpenSelection,&itemToOpen); if (itemToOpen.descriptorType == typeFSS) { // you may open the file as described by 'itemToOpen', or do whatever you want with it: AEDisposeDesc(&itemToOpen); } break; } case kNavCtlCancel: theErr = NavCustomControl(callBackParms->context,kNavCtlCancel,NULL); break; case kNavCtlAccept: theErr = NavCustomControl(callBackParms->context,kNavCtlAccept,NULL); break; } } // ***************************************************************************** // * // * HandleCustomMouseDown() // * // ***************************************************************************** void HandleCustomMouseDown(NavCBRecPtr callBackParms) { OSErr theErr = noErr; ControlHandle whichControl; Point where = callBackParms->eventData.event->where; short theItem = 0; UInt16 firstItem = 0; short realItem = 0; short partCode = 0; GlobalToLocal(&where); theItem = FindDialogItem(callBackParms->window,where); // get the item number of the control partCode = FindControl(where,callBackParms->window,&whichControl); // get the control itself // ask NavServices for the first custom control's ID: if (callBackParms->context != 0) // always check to see if the context is correct { theErr = NavCustomControl(callBackParms->context,kNavCtlGetFirstControlID,&firstItem); realItem = theItem - firstItem + 1; // map it to our DITL constants: } if (realItem == kPopupCommand) HandleCommandPopup(whichControl,callBackParms); } // ***************************************************************************** // * // * DoAddItem() // * // ***************************************************************************** Boolean DoAddItem(unsigned char* theData, short size) { if (theData && gListItem) { Cell theCell = {0,0}; short theRow; p2cstr((StringPtr)theData); if (LGetSelect(true,&theCell,gListItem)) // de-select all the currently selected items { LSetSelect(false,theCell,gListItem); // deselect the first old item theCell.v++; // move down one cell while (LGetSelect(true,&theCell,gListItem)) // find current selected item { if (LGetSelect(true,&theCell,gListItem)) LSetSelect(false,theCell,gListItem);// deselect the next old item theCell.v++; } } // insert data into (col 0, row x), add the item theRow = LAddRow(1,256,gListItem); // insert item into the new row theCell.h = 0; theCell.v = theRow; LSetCell(theData,size,theCell,gListItem); gNumItems++; c2pstr((Ptr)theData); LSetSelect(true,theCell,gListItem); // select the newly added item LAutoScroll(gListItem); // scroll if necessary return true; } else return false; } // ***************************************************************************** // * // * DoSearch() // * // ***************************************************************************** Boolean DoSearch( AEDesc searchDesc ) { OSErr theErr = noErr; Boolean found = false; FSSpec finalSpec; Cell theCell = {0,0}; short theLen; if ((theErr = AEGetDescData ( &searchDesc, NULL, &finalSpec, sizeof ( FSSpec ), NULL )) == noErr) { theLen = finalSpec.name[0]; p2cstr((StringPtr)finalSpec.name); if (gListItem) if (LSearch((Ptr)finalSpec.name, theLen, NULL, &theCell, gListItem)) found = true; c2pstr((Ptr)finalSpec.name); } return found; } // ***************************************************************************** // * // * HandleAdd() // * // ***************************************************************************** void HandleAdd( NavCBRecPtr callBackParms, AEDescList theSelectionList ) { OSErr theErr = noErr; long count = 0; FSSpec finalSpec; UInt16 firstItem = 0; Cell beforeCell = {0,0}; Handle itemH; Rect itemRect; short itemType; if ((theErr = AECountItems( &theSelectionList, &count )) == noErr) for ( long index=1; index<=count; index++ ) { AEDesc theItemDesc; if ((theErr = AEGetNthDesc( &theSelectionList, index, typeFSS, NULL, &theItemDesc )) == noErr) { // put something in there: if ((theErr = AEGetDescData ( &theItemDesc, NULL, &finalSpec, sizeof ( FSSpec ), NULL )) == noErr) if (!DoSearch( theItemDesc )) { DoAddItem( finalSpec.name, finalSpec.name[0] ); if (LGetSelect( true, &beforeCell, gListItem )) { // adjust the remove buttons: if ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetFirstControlID, &firstItem )) == noErr) { GetDialogItem( callBackParms->window, firstItem + iRemoveButton + 1, &itemType, &itemH, &itemRect ); HiliteControl( (ControlHandle)itemH, 0 ); GetDialogItem( callBackParms->window, firstItem + iRemoveAllButton + 1, &itemType, &itemH, &itemRect ); HiliteControl( (ControlHandle)itemH, 0 ); } } } else SysBeep(5); // item already in list AEDisposeDesc( &theItemDesc ); } } } // ***************************************************************************** // * // * HandleRemoveAll() // * // ***************************************************************************** void HandleRemoveAll( NavCBRecPtr callBackParms ) { OSErr theErr = noErr; UInt16 firstItem = 0; Handle itemH; Rect itemRect; short itemType; if ( gListItem != NULL ) { LDelRow( 0, 0, gListItem ); gNumItems = 0; // adjust the Remove Buttons if ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetFirstControlID, &firstItem )) == noErr) { GetDialogItem( callBackParms->window, firstItem + iRemoveButton + 1, &itemType, &itemH, &itemRect ); HiliteControl( (ControlHandle)itemH, 255 ); GetDialogItem( callBackParms->window, firstItem + iRemoveAllButton + 1, &itemType, &itemH, &itemRect ); HiliteControl( (ControlHandle)itemH, 255 ); } } } // ***************************************************************************** // * // * HandleRemove() // * // ***************************************************************************** void HandleRemove( NavCBRecPtr callBackParms ) { OSErr theErr = noErr; Cell theCell = {0,0}; long theID = 0; Boolean result = false; UInt16 firstItem = 0; Handle removeH,removeAllH; Rect itemRect; short itemType; if (gListItem != NULL) { LGetSelect( true, &theCell,gListItem ); // find the first selected item LDelRow(1,theCell.v, gListItem ); gNumItems--; while (LGetSelect( true, &theCell, gListItem )) // find next selected item { LDelRow( 1, theCell.v, gListItem ); gNumItems--; } // adjust the "Remove Button": if ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetFirstControlID, &firstItem )) == noErr) { GetDialogItem( callBackParms->window, firstItem + iRemoveButton + 1, &itemType, &removeH, &itemRect ); GetDialogItem( callBackParms->window, firstItem + iRemoveAllButton + 1, &itemType, &removeAllH, &itemRect ); theCell.v = 0; theCell.h = 0; LSetSelect (true, theCell, gListItem); if (LGetSelect( true, &theCell, gListItem )) { HiliteControl( (ControlHandle)removeH, 0 ); HiliteControl( (ControlHandle)removeAllH, 0 ); } else { HiliteControl( (ControlHandle)removeH, 255 ); HiliteControl( (ControlHandle)removeAllH, 255 ); } } } } // ***************************************************************************** // * // * DoListMouseDown() // * // ***************************************************************************** Boolean DoListMouseDown( NavCBRecPtr callBackParms ) { Cell whichCell={0,0}, beforeCell={0,0}; Point myPt = callBackParms->eventData.event->where; Boolean result = true; Handle removeH,removeAllH; Rect itemRect; short itemType; UInt16 firstItem = 0; OSErr theErr = noErr; SetPort( callBackParms->window ); GlobalToLocal( &myPt ); Boolean doubleClick = LClick(myPt, callBackParms->eventData.event->modifiers, gListItem ); whichCell = LLastClick( gListItem ); // adjust the "Remove Button": if ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetFirstControlID, &firstItem )) == noErr) { GetDialogItem( callBackParms->window, firstItem + iRemoveButton + 1, &itemType, &removeH, &itemRect ); GetDialogItem( callBackParms->window, firstItem + iRemoveAllButton + 1, &itemType, &removeAllH, &itemRect ); } if (LGetSelect( true, &beforeCell, gListItem )) { HiliteControl( (ControlHandle)removeH, 0 ); HiliteControl( (ControlHandle)removeAllH, 0 ); } else { HiliteControl( (ControlHandle)removeH, 255 ); HiliteControl( (ControlHandle)removeAllH, 255 ); } return result; } // ***************************************************************************** // * // * HandleAddRemoveCustomMouseDown() // * // ***************************************************************************** void HandleAddRemoveCustomMouseDown(NavCBRecPtr callBackParms) { OSErr theErr = noErr; ControlHandle whichControl; Point where = callBackParms->eventData.event->where; short theItem = 0; UInt16 firstItem = 0; short realItem = 0; short partCode = 0; AEDescList selectionList; GlobalToLocal(&where); theItem = FindDialogItem( callBackParms->window, where ); // get the item number of the control partCode = FindControl( where, callBackParms->window, &whichControl ); // get the control itself // ask NavServices for the first custom control's ID: if ( callBackParms->context != 0 && ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetFirstControlID, &firstItem )) == noErr)) // always check to see if the context is correct { realItem = theItem - firstItem; // map it to our DITL constants: AdjustAddButton( callBackParms ); switch (realItem) { case iList: DoListMouseDown( callBackParms ); break; case iAddButton: if ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetSelection, &selectionList )) == noErr) { HandleAdd( callBackParms, selectionList ); AEDisposeDesc( &selectionList ); } break; case iRemoveButton: HandleRemove( callBackParms ); break; case iRemoveAllButton: HandleRemoveAll( callBackParms ); break; case iDoneButton: theErr = NavCustomControl(callBackParms->context,kNavCtlCancel,&firstItem); break; } } } // ***************************************************************************** // * // * myEventProc() // * // ***************************************************************************** pascal void myCustomEventProc( NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, NavCallBackUserData callBackUD) { OSErr theErr = noErr; WindowPtr pWindow = NULL; Document** docList; Document* theDoc = NULL; short index = 0; if (callBackUD != 0) switch (callBackSelector) { case kNavCBEvent: { docList = (Document**)callBackUD; if (docList != NULL) switch (callBackParms->eventData.event->what) { case mouseDown: HandleCustomMouseDown(callBackParms); break; case updateEvt: pWindow = (WindowPtr)callBackParms->eventData.event->message; theDoc = docList[index]; if (theDoc != NULL) { while ((theDoc->theWindow != pWindow) && (docList[index] != NULL)) { index++; theDoc = docList[index]; } theDoc = docList[index]; if (theDoc != NULL) UpdateWindow(theDoc); } break; default: break; } break; } case kNavCBCustomize: { // here are the desired dimensions for our custom area: short neededWidth = callBackParms->customRect.left + kCustomWidth; short neededHeight = callBackParms->customRect.top + kCustomHeight; // check to see if this is the first round of negotiations: if ((callBackParms->customRect.right == 0) && (callBackParms->customRect.bottom == 0)) { // it is, so tell NavServices what dimensions we want: callBackParms->customRect.right = neededWidth; callBackParms->customRect.bottom = neededHeight; } else { // we are in the middle of negotiating: if (gLastTryWidth != callBackParms->customRect.right) if (callBackParms->customRect.right < neededWidth) // is NavServices width too small for us? callBackParms->customRect.right = neededWidth; if (gLastTryHeight != callBackParms->customRect.bottom) // is NavServices height too small for us? if (callBackParms->customRect.bottom < neededHeight) callBackParms->customRect.bottom = neededHeight; } // remember our last size so the next time we can re-negotiate: gLastTryWidth = callBackParms->customRect.right; gLastTryHeight = callBackParms->customRect.bottom; break; } case kNavCBStart: { short itemType; Rect itemRect; Handle itemH; UInt16 firstItem = 0; short realItem = 0; // add the rest of the custom controls via the DITL resource list: gDitlList = GetResource('DITL',kControlListID); if ((gDitlList != NULL)&&(ResError() == noErr)) if ((theErr = NavCustomControl(callBackParms->context,kNavCtlAddControlList,gDitlList)) == noErr) { theErr = NavCustomControl(callBackParms->context,kNavCtlGetFirstControlID,&firstItem); // ask NavServices for our first control ID // set the command popup selection: realItem = firstItem + kPopupCommand; GetDialogItem(callBackParms->window,realItem,&itemType,&itemH,&itemRect); SetControlValue((ControlHandle)itemH,1); } // the dialog is starting up, let's override the default popup menu selection: UInt16 itemToSelect = kNavAllReadableFiles; theErr = NavCustomControl(callBackParms->context,kNavCtlSelectAllType,&itemToSelect); break; } case kNavCBTerminate: // release our appended popup menu: if (gDitlList) ReleaseResource(gDitlList); if (gPopupMenu) DisposeMenu(gPopupMenu); break; } } // ***************************************************************************** // * // * AdjustAddButton() // * // ***************************************************************************** void AdjustAddButton( NavCBRecPtr callBackParms ) { OSErr theErr = noErr; AEDescList selectionList; Handle itemH; Rect itemRect; short itemType; FSSpec finalSpec; AEDesc resultDesc; UInt16 firstItem = 0; long itemCount = 0; // update the button states: if ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetFirstControlID, &firstItem )) == noErr) if ((theErr = NavCustomControl( callBackParms->context, kNavCtlGetSelection, &selectionList )) == noErr) { GetDialogItem( callBackParms->window, firstItem + iAddButton + 1, &itemType, &itemH, &itemRect ); if (( theErr = AECountItems( &selectionList, &itemCount )) == noErr ) { if (itemCount == 1) { if ((theErr = AEGetNthDesc( &selectionList, 1, typeFSS, NULL, &resultDesc)) == noErr) { if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalSpec, sizeof ( FSSpec ), NULL )) == noErr) { if (finalSpec.name[0] == 0) HiliteControl( (ControlHandle)itemH, 255 ); // the object is a folder, disable add: else HiliteControl( (ControlHandle)itemH, 0 ); // the object is a file, enable add: } AEDisposeDesc(&resultDesc); } } else HiliteControl( (ControlHandle)itemH, 0 ); // we have current selection } else HiliteControl( (ControlHandle)itemH, 255 ); // no current selection AEDisposeDesc( &selectionList ); } } // ***************************************************************************** // * // * myCustomAddRemoveEventProc() // * // ***************************************************************************** pascal void myCustomAddRemoveEventProc( NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, NavCallBackUserData callBackUD) { OSErr theErr = noErr; WindowPtr pWindow = (WindowPtr)callBackParms->eventData.event->message; // for managing our windows: Document** docList; Document* theDoc = NULL; // for handling dialog items: short itemType; Rect itemRect; Handle itemH; UInt16 firstItem = 0; short realItem = 0; short hOffset = 0; short vOffset = 0; if (callBackUD != 0) switch (callBackSelector) { case kNavCBEvent: { switch (callBackParms->eventData.event->what) { case mouseDown: HandleAddRemoveCustomMouseDown(callBackParms); break; case updateEvt: if (pWindow == callBackParms->window) { // ask NavServices for our first control ID if ((theErr = NavCustomControl(callBackParms->context, kNavCtlGetFirstControlID, &firstItem )) == noErr) { LUpdate( callBackParms->window->visRgn, gListItem ); // set the command popup selection: realItem = firstItem + iList + 1; GetDialogItem(callBackParms->window,realItem,&itemType,&itemH,&itemRect); InsetRect(&itemRect,-1,-1); FrameRect(&itemRect); } } else { short index = 0; docList = (Document**)callBackUD; if (docList != NULL) { theDoc = docList[index]; if (theDoc != NULL) { while ((theDoc->theWindow != pWindow) && (docList[index] != NULL)) { index++; theDoc = docList[index]; } theDoc = docList[index]; if (theDoc != NULL) UpdateWindow(theDoc); } } } break; default: break; } break; } case kNavCBCustomize: { // here are the desired dimensions for our custom area: short neededWidth = callBackParms->customRect.left + kAddRemoveCustomWidth; short neededHeight = callBackParms->customRect.top + kAddRemoveCustomHeight; // check to see if this is the first round of negotiations: if ((callBackParms->customRect.right == 0) && (callBackParms->customRect.bottom == 0)) { // it is, so tell NavServices what dimensions we want: callBackParms->customRect.right = neededWidth; callBackParms->customRect.bottom = neededHeight; } else { // we are in the middle of negotiating: if (gLastTryWidth != callBackParms->customRect.right) if (callBackParms->customRect.right < neededWidth) // is NavServices width too small for us? callBackParms->customRect.right = neededWidth; if (gLastTryHeight != callBackParms->customRect.bottom) // is NavServices height too small for us? if (callBackParms->customRect.bottom < neededHeight) callBackParms->customRect.bottom = neededHeight; } // remember our last size so the next time we can re-negotiate: gLastTryWidth = callBackParms->customRect.right; gLastTryHeight = callBackParms->customRect.bottom; break; } case kNavCBAdjustRect: if (gListItem != NULL) { Rect newRect; Rect finalRect; Cell theCell = {0,0}; ControlHandle scrollBar = (*gListItem)->vScroll; theErr = NavCustomControl(callBackParms->context, kNavCtlGetFirstControlID, &firstItem ); // ask NavServices for our first control ID realItem = firstItem + iList + 1; GetDialogItem( callBackParms->window, realItem, &itemType, &itemH, &itemRect ); // change the list's rect: newRect = itemRect; newRect.right -= 15; (*gListItem)->rView = newRect; // change the list's scrollbar control: InsetRect(&itemRect,-1,-1); SetRect( &finalRect, itemRect.right-16, itemRect.top, itemRect.right, itemRect.bottom ); (*scrollBar)->contrlRect = finalRect; LUpdate( callBackParms->window->visRgn, gListItem ); LActivate( true, gListItem ); gOriginalRect = callBackParms->customRect; } break; case kNavCBStart: // add the rest of the custom controls via the DITL resource list: gDitlList = GetResource('DITL',kAddRemoveControlListID); if (gDitlList != NULL && ResError() == noErr) if ((theErr = NavCustomControl(callBackParms->context,kNavCtlAddControlList,gDitlList)) == noErr) { theErr = NavCustomControl(callBackParms->context,kNavCtlGetFirstControlID,&firstItem); // ask NavServices for our first control ID realItem = firstItem + iList + 1; GetDialogItem(callBackParms->window,realItem,&itemType,&itemH,&itemRect); Rect tempRect; // used as modify the list rect Rect dataBounds; // bounds of the list Point theCell; tempRect = itemRect; tempRect.right = tempRect.right - 15; if (tempRect.right <= (tempRect.left + 15)) tempRect.right = tempRect.left + 15; InsetRect(&tempRect,-1,-1); FrameRect(&tempRect); InsetRect(&tempRect,1,1); SetRect(&dataBounds,0,0,1,0); // empty list theCell.h = tempRect.right - tempRect.left; theCell.v = 16; gListItem = NULL; gListItem = LNew(&tempRect,&dataBounds,theCell,0,callBackParms->window,true,false,false,true); if (gListItem != NULL) { gNumItems = 0; (*gListItem)->selFlags = lNoNilHilite + lUseSense; LSetDrawingMode(true,gListItem); // list gets automatically drawn theCell.v = 0; theCell.h = 0; LSetSelect(true,theCell,gListItem); // default selection to 0,0 LAutoScroll(gListItem); // keep scrolling so the first property is visible (void)LClick(theCell,0,gListItem); // click in negative space to indicate the list is blank } // disable the "Remove All Button": GetDialogItem( callBackParms->window, firstItem + iRemoveAllButton + 1, &itemType, &itemH, &itemRect ); HiliteControl( (ControlHandle)itemH, 255 ); // disable the "Remove Button": GetDialogItem( callBackParms->window, firstItem + iRemoveButton + 1, &itemType, &itemH, &itemRect ); HiliteControl( (ControlHandle)itemH, 255 ); AdjustAddButton( callBackParms ); } break; case kNavCBTerminate: if (gDitlList) ReleaseResource(gDitlList); if (gListItem != NULL) LDispose(gListItem); gListItem = NULL; gNumItems = 0; break; } } // ***************************************************************************** // * // * DoCustomAddRemove() // * // * This is a "primitive" example of how you would add an Add/Remove // * human interface to NavGetFile(). // * // ***************************************************************************** OSErr DoCustomAddRemove( ) { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavTypeListHandle typeList = NULL; long count = 0; NavEventUPP eventUPP = NewNavEventProc(myCustomAddRemoveEventProc); // default behavior for browser and dialog: theErr = NavGetDefaultDialogOptions(&dialogOptions); GetIndString((unsigned char*)&dialogOptions.windowTitle,rAppStringsID,sAddRemoveTitle); dialogOptions.dialogOptionFlags += kNavNoTypePopup; dialogOptions.dialogOptionFlags -= kNavAllowPreviews; dialogOptions.dialogOptionFlags += kNavDontAutoTranslate; theErr = NavGetFile(NULL, // use system's default location &theReply, &dialogOptions, eventUPP, NULL, // no custom previews NULL, NULL, (NavCallBackUserData)&gDocumentList); DisposeRoutineDescriptor(eventUPP); if (theReply.validRecord && theErr == noErr) { // since we allow for multiple objects to be returned, // grab the target FSSpecs from 'theReply.fileRef' list for opening: FSSpec finalFSSpec; AEDesc resultDesc; // we are ready to open the document(s), grab information about each file for opening: theErr = AECountItems(&(theReply.selection),&count); for (long index=1;index<=count;index++) { if ((theErr = AEGetNthDesc(&(theReply.selection),index,typeFSS,NULL,&resultDesc)) == noErr) if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalFSSpec, sizeof ( FSSpec ), NULL )) == noErr) { //.. } theErr = AEDisposeDesc(&resultDesc); } theErr = NavDisposeReply(&theReply); // clean up after ourselves } return theErr; } // ***************************************************************************** // * // * DoCustomOpen() // * // ***************************************************************************** OSErr DoCustomOpen() { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavTypeListHandle typeList = NULL; long count = 0; NavEventUPP eventUPP = NewNavEventProc(myCustomEventProc); // default behavior for browser and dialog: theErr = NavGetDefaultDialogOptions(&dialogOptions); GetIndString((unsigned char*)&dialogOptions.clientName,rAppStringsID,sApplicationName); typeList = (NavTypeListHandle)GetResource(kOpenRsrcType,kOpenRsrcID); theErr = NavGetFile(NULL, // use system's default location &theReply, &dialogOptions, eventUPP, NULL, // no custom previews NULL, typeList, (NavCallBackUserData)&gDocumentList); DisposeRoutineDescriptor(eventUPP); if (theReply.validRecord && theErr == noErr) { // since we allow for multiple objects to be returned, // grab the target FSSpecs from 'theReply.fileRef' list for opening: FSSpec finalFSSpec; AEDesc resultDesc; FInfo fileInfo; // we are ready to open the document(s), grab information about each file for opening: theErr = AECountItems(&(theReply.selection),&count); for (long index=1;index<=count;index++) { if ((theErr = AEGetNthDesc(&(theReply.selection),index,typeFSS,NULL,&resultDesc)) == noErr) { if ((theErr = AEGetDescData ( &resultDesc, NULL, &finalFSSpec, sizeof ( FSSpec ), NULL )) == noErr) // decide if the doc we are opening is a 'PICT' or 'TEXT': if ((theErr = FSpGetFInfo(&finalFSSpec,&fileInfo)) == noErr) { if (fileInfo.fdType == kFileType) (void)DoOpenFile(&finalFSSpec,false); else if (fileInfo.fdType == kFileTypePICT) (void)DoOpenFile(&finalFSSpec,true); else { // error: // if we got this far, the document is a type we can't open and // (most likely) built-in translation was turned off. // You can alert the user that this returned selection or file spec // needs translation. } } theErr = AEDisposeDesc(&resultDesc); } } theErr = NavDisposeReply(&theReply); // clean up after ourselves } if (typeList != NULL) ReleaseResource((Handle)typeList); return theErr; } // ***************************************************************************** // * // * DoAbout() // * // ***************************************************************************** void DoAbout() { GrafPtr savePort; DialogPtr aboutDialog; short itemHit = 0; Handle itemH; short itemType; Rect itemRect; SetCursor(&qd.arrow); aboutDialog = GetNewDialog(rAboutID,nil,(WindowRef)-1); GetPort(&savePort); SetPort((GrafPtr)aboutDialog); AdornButton(aboutDialog,dOK); GetDialogItem(aboutDialog,iIconSuite,&itemType,&itemH,&itemRect); DrawIconSuite(rIconSuite,itemRect); do ModalDialog(nil,&itemHit); while(itemHit != dOK); SetPort(savePort); DisposeDialog(aboutDialog); } // ***************************************************************************** // * // * DoMenuCommand() // * // ***************************************************************************** void DoMenuCommand(long select) { short theMenuID, theItem; MenuHandle theMenu; Str255 theName; WindowPtr theWindow; Document* theDocument = nil; OSStatus theErr = noErr; gCanUndoDrag = slUndoDrag; AdjustMenus(); theDocument = IsDocumentWindow(theWindow = (WindowPtr)FrontWindow()); theItem = LoWord(select); theMenuID = HiWord(select); theMenu = GetMenuHandle(theMenuID); switch(theMenuID) { case idAppleMenu: switch(theItem) { case AboutItem: DoAbout(); break; default: GetMenuItemText(GetMenuHandle(idAppleMenu),theItem,(unsigned char*)&theName); OpenDeskAcc(theName); } break; case idFileMenu: switch(theItem) { case NewItem: DoNewDocument(false); AdjustMenus(); break; case OpenItem: if (gNavServicesExists) theErr = DoOpenDocument(); else (void)DoOpenDocumentTheOldWay(); AdjustMenus(); break; case CloseItem: if (theDocument) { CloseDocument(theDocument,false); AdjustMenus(); DrawMenuBar(); } break; case SaveItem: if (theDocument) DoSaveDocument(theDocument); break; case SaveACopyItem: if (theDocument) { if (gNavServicesExists) theErr = SaveACopyDocument(theDocument); else (void)SaveACopyDocumentTheOldWay(theDocument); if (theErr == memFullErr) { (void)SaveACopyDocumentTheOldWay(theDocument); theErr = noErr; } } break; case RevertItem: DisableUndoDrag(); if (theDocument) { if (gNavServicesExists) DoRevertDocument(theDocument); else DoRevertDocumentTheOldWay(theDocument); } break; case DictionaryItem: theErr = DoSelectDictionary(); break; case QuitItem: gQuitting = true; while ((gQuitting) && (theDocument = IsDocumentWindow((WindowPtr)FrontWindow()))) CloseDocument(theDocument,true); if (gQuitting) gQuit = true; break; } break; case idEditMenu: switch(theItem) { case iUndo: DoUndoDrag(); break; case iCut: if ((theDocument)&&(theDocument->theTE != NULL)) { DisableUndoDrag(); myTECut(theDocument->theTE); } break; case iCopy: if (theDocument) TECopy(theDocument->theTE); break; case iPaste: if ((theDocument)&&(theDocument->theTE != NULL)) if (!DoPaste()) { DisableUndoDrag(); myTEPaste(theDocument->theTE,0L,0L); } break; case iClear: if ((theDocument)&&(theDocument->theTE != NULL)) { DisableUndoDrag(); TEDelete(theDocument->theTE); } break; case iSelectAll: if ((theDocument)&&(theDocument->theTE != NULL)) DoSelectAllDocument(theDocument); break; } break; case idUtilsMenu: switch (theItem) { case iSelectDir: theErr = DoSelectDirectory(); break; case iSelectVol: theErr = DoSelectVolume(); break; case iSelectObject: theErr = DoSelectObject(); break; case iCreateFolder: theErr = DoCreateFolder(); break; case iCustomOpen: theErr = DoCustomOpen(); break; case iAddFiles: theErr = DoCustomAddRemove(); break; } break; } if ( theErr == memFullErr ) DoLowMemAlert( ); if (theDocument = IsDocumentWindow((WindowPtr)FrontWindow())) if (theDocument->theTE != NULL) TEGetHiliteRgn(theDocument->hiliteRgn,theDocument->theTE); HiliteMenu(0); gCanUndoDrag = slCantUndo; }